/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bulkmailer.email.scanner;

import bulkmailer.beans.AccountSettings;
import bulkmailer.beans.ServerSettings;
import bulkmailer.app.main.UI;
import bulkmailer.email.addr.manager.EMailAddressManager;
import java.sql.Connection;
import java.util.Properties;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.mail.Address;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.swing.JOptionPane;
import org.apache.log4j.Logger;

/**
 *
 * @author ravi
 */
public class MailScanner extends Thread {

    private String userName = null;
    private String password = null;
    private int serverPort = -1;
    private String serverAddress = null;
    private String authType = null;
    private String folderName = null;
    private Connection con = null;

    public void fetchMails(AccountSettings accountSettings, ServerSettings serverSettings) {
        Properties properties = new Properties();
        Session session = Session.getDefaultInstance(properties, null);
        setServerSettings(serverSettings);
        setAccountSettings(accountSettings);
        Folder folder = null;
        try {
            Store store = session.getStore(authType);
            store.connect(serverSettings.getImapServerAddress(),
                    serverSettings.getImapPort(),
                    accountSettings.getEmailId(),
                    accountSettings.getPassword());
            Folder folders[] = store.getDefaultFolder().list();

            if (serverSettings.isTakeAllFolders() == true) {
                for (Folder fd : folders) {
                    Logger.getRootLogger().debug(fd.getName());
                    UI.appsUi.getFolderLbl().setText(fd.getName());
                    if (fd.getName().equals("[Gmail]")) {
                        continue;
                    }
                    folder = store.getFolder(fd.getName());
                    this.getMessagesFromFolder(folder);
                }
            } else {
                boolean isFound = false;
                for (Folder fd : folders) {
                    if (this.folderName.equals(fd.getName())) {
                        folder = store.getFolder(this.folderName);
                        UI.appsUi.getFolderLbl().setText(fd.getName());
                        this.getMessagesFromFolder(folder);
                        isFound = true;
                    }
                }
                if (isFound == false) {
                    Logger.getRootLogger().debug("invalid folder specified");
                    JOptionPane.showMessageDialog(null,
                        "Folder name invalid..",
                        "",
                        JOptionPane.ERROR_MESSAGE);
                }
            }
            store.close();
        } catch (MessagingException ex) {
            Logger.getRootLogger().error("could not connect to internet, check connection settings");
        }
    }

    public void getMessagesFromFolder(Folder folder) {
        TreeSet<String> set = new TreeSet<String>();
        TreeSet<String> totalFound = new TreeSet<String>();
        Message[] messageArray = null;
        try {
            Logger.getRootLogger().debug("fetching from: " + folder.getName());
            folder.open(Folder.READ_ONLY);
            messageArray = folder.getMessages();
            UI.appsUi.getProgressBar().setMaximum(messageArray.length);
            int allIds = 0;
            for (int i = 0, n = messageArray.length; i < n; i++) {
                Logger.getRootLogger().debug("fetching message : " + (i + 1));
                if (i % 1 == 0 && !set.isEmpty()) {
                    Logger.getRootLogger().debug("pushing mails");
                    EMailAddressManager mailPusher = new EMailAddressManager();
                    mailPusher.pushMail(set);
                    set = new TreeSet<String>();
                }
                UI.appsUi.setTotalMsgLbl(messageArray.length);
                UI.appsUi.setFetchLbl(i);
                UI.appsUi.setUniqueLbl(totalFound.size());
                UI.appsUi.getProgressBar().setValue(i);
                Address[] addressFrom = messageArray[i].getFrom();
                Address[] addressAllRecpt = messageArray[i].getAllRecipients();

                if (addressFrom != null) {
                    allIds += addressFrom.length;
                    for (int j = 0; j < addressFrom.length; j++) {
                        UI.appsUi.setAllLbl(allIds);
                        if (extractEmail(addressFrom[j].toString()).length() < 30) {
                            totalFound.add(extractEmail(addressFrom[j].toString()));
                            set.add(extractEmail(addressFrom[j].toString()));
                        } else {
                            Logger.getRootLogger().debug(extractEmail(addressFrom[j].toString()));
                        }
                    }
                }
                if (addressAllRecpt != null) {
                    allIds += addressAllRecpt.length;
                    for (int j = 0; j < addressAllRecpt.length; j++) {
                        if (extractEmail(addressAllRecpt[j].toString()).length() < 30) {
                            totalFound.add(extractEmail(addressAllRecpt[j].toString()));
                            set.add(extractEmail(addressAllRecpt[j].toString()));
                        } else {
                            Logger.getRootLogger().debug(extractEmail(addressAllRecpt[j].toString()));
                        }
                    }
                }
            }
            folder.close(false);
        } catch (MessagingException ex) {
            Logger.getRootLogger().error(ex.toString());
        } catch (NullPointerException ex) {
            Logger.getRootLogger().error("null address list was found...continueing...");
        }
    }

    public String extractEmail(String email) {
        String expression = "([\\w\\-]([\\.\\w])+[\\w]+@([\\w\\-]+\\.)+[A-Za-z]{2,4})";

        CharSequence inputStr = email;
        Pattern pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(inputStr);
        if (matcher.matches()) {
            Logger.getRootLogger().debug("nalid: " + email);
        } else {
            Logger.getRootLogger().debug("not valid by matcher: " + email);
        }

        int indexOfLt = email.lastIndexOf("<");
        int indexOfGt = email.lastIndexOf(">");
        Logger.getRootLogger().debug(indexOfLt + " " + indexOfGt);
        if ((indexOfLt > 0) && (indexOfGt > 0)) {
            email = email.subSequence(indexOfLt + 1, indexOfGt).toString();
            if (verifyMailId(email)) {
            }
        }
        return email;
    }

    public void setServerSettings(ServerSettings serverSettings) {
        System.out.println(serverSettings);
        this.serverPort = serverSettings.getImapPort();
        this.serverAddress = serverSettings.getImapServerAddress();
        this.folderName = serverSettings.getFolderName();
        if (serverSettings.isSecureAuth()) {
            this.authType = "imaps";
        } else {
            this.authType = "imap";
        }

    }

    public void setAccountSettings(AccountSettings accountSettings) {
        this.userName = accountSettings.getEmailId();
        this.password = accountSettings.getPassword();
    }

    public boolean verifyMailId(String email) {
        boolean isValid = false;
        String expression = "^[\\w\\.-]+@([\\w\\-]+\\.)+[A-Z]{2,4}$";
        CharSequence inputStr = email;        
        Pattern pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(inputStr);
        if (matcher.matches()) {
            isValid = true;
        }
        return isValid;
    }

    /**
     * @return the con
     */
    public Connection getCon() {
        return con;
    }

    /**
     * @param con the con to set
     */
    public void setCon(Connection con) {
        this.con = con;
    }
}
